package com.xdf.xzymanagementsystem.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @program: xzy-management-system
 * @description: 查询帮助类
 * @author: 张柯
 * @create: 2020-12-31 14:42:38
 **/
public class Example<T> {
    /**
     * 是否去重
     */
    private boolean distinct;

    /**
     * 自定义返回列
     */
    private String[] resultColumns;

    /**
     * 开始行
     */
    private Long startRow;

    /**
     * 结果集数量
     */
    private Long rowSize;

    /**
     * 排序
     */
    private String orderSql;

    /**
     * 汇总
     */
    private String groupSql;

    /**
     * where子句
     */
    private List<Example.WhereCondition<?>> whereCondition;

    /**
     * 正序
     */
    public static final String ASC = "ASC";

    /**
     * 倒序
     */
    public static final String DESC = "DESC";


    /**
     * 获取是否去重(使用distinct)
     *
     * @return
     */
    public boolean isDistinct() {
        return distinct;
    }

    /**
     * 设置去重(使用distinct)
     *
     * @param distinct
     * @return
     */
    public Example<T> setDistinct(boolean distinct) {
        this.distinct = distinct;
        return this;
    }

    /**
     * 获取结果集列名
     *
     * @return
     */
    public String[] getResultColumns() {
        return resultColumns;
    }

    /**
     * 设置结果集返回列列名
     *
     * @param resultColumns
     * @return
     */
    public Example<T> setResultColumns(String[] resultColumns) {
        this.resultColumns = resultColumns;
        return this;
    }

    /**
     * 获取开始行
     *
     * @return
     */
    public Long getStartRow() {
        return startRow;
    }

    /**
     * 设置开始行
     *
     * @param startRow
     * @return
     */
    public Example<T> setStartRow(Long startRow) {
        this.startRow = startRow;
        return this;
    }

    /**
     * 获取条目数
     *
     * @return
     */
    public Long getRowSize() {
        return rowSize;
    }

    /**
     * 设置查询数据条目数
     *
     * @param rowSize
     * @return
     */
    public Example<T> setRowSize(Long rowSize) {
        this.rowSize = rowSize;
        return this;
    }

    /**
     * 获取orderby条件
     *
     * @return
     */
    public String getOrderSql() {
        return orderSql;
    }

    /**
     * 设置orderby条件
     *
     * @param conditions
     * @return
     */
    public Example<T> setOrderSql(OrderByCondition... conditions) {
        if (conditions == null || conditions.length == 0) {
            return this;
        }
        StringBuilder sql = new StringBuilder();
        for (int index = 0; index < conditions.length; index++) {
            if (index == 0) {
                sql.append(" ORDER BY ")
                        .append(conditions[index].getColumn())
                        .append(" ")
                        .append(isEmpty(conditions[index].getMode()) ? Example.ASC : conditions[index].getMode());
            } else {
                sql.append(",")
                        .append(conditions[index].getColumn())
                        .append(" ")
                        .append(isEmpty(conditions[index].getMode()) ? Example.ASC : conditions[index].getMode());
            }
        }
        this.orderSql = sql.toString();
        return this;
    }

    /**
     * 获取groupby条件
     *
     * @return
     */
    public String getGroupSql() {
        return groupSql;
    }

    /**
     * 设置groupby条件
     *
     * @param conditions
     * @return
     */
    public Example<T> setGroupSql(GroupByCondition... conditions) {
        if (conditions == null || conditions.length == 0) {
            this.groupSql = null;
            return this;
        }
        StringBuilder sql = new StringBuilder();
        for (int i = 0; i < conditions.length; i++) {
            if (i == 0) {
                sql.append(" GROUP BY ")
                        .append(conditions[i].getColumn())
                        .append(" ")
                        .append(isEmpty(conditions[i].getMode()) ? "" : conditions[i].getMode());
            } else {
                sql.append(",")
                        .append(conditions[i].getColumn())
                        .append(" ")
                        .append(isEmpty(conditions[i].getMode()) ? "" : conditions[i].getMode());
            }
        }
        this.groupSql = sql.toString();
        return this;
    }

    /**
     * 获取where条件
     *
     * @return
     */
    public List<WhereCondition<?>> getWhereCondition() {
        return whereCondition;
    }

    /**
     * 设置where子句
     *
     * @param whereCondition
     * @return
     */
    public Example<T> addWhereCondition(WhereCondition<?>... whereCondition) {
        if (whereCondition == null || whereCondition.length == 0) {
            return this;
        }
        if (this.whereCondition == null)
            this.whereCondition = new ArrayList<>();
        for (WhereCondition item : whereCondition) {
            this.whereCondition.add(item);
        }
        return this;
    }

    public Example() {
        super();
    }

    /**
     * where条件集
     *
     * @param <T>
     */
    public static class WhereCondition<T> {
        /**
         * where子句条件前缀(类似id=)
         */
        private String prefix;
        /**
         * 后缀
         */
        private String suffix;
        /**
         * 值
         */
        private T value;
        /**
         * 多个值数组
         */
        private Object[] values;
        /**
         * 自定义查询条件
         */
        private List<WhereCondition<?>> customRequire;

        public WhereCondition(String prefix, String suffix) {
            super();
            this.prefix = prefix;
            this.suffix = suffix;
        }

        public WhereCondition(String prefix, String suffix, List<WhereCondition<?>> customRequire) {
            this.prefix = prefix;
            this.suffix = suffix;
            this.customRequire = customRequire;
        }

        public WhereCondition(String prefix, T value) {
            super();
            this.prefix = prefix;
            this.value = value;
        }

        public WhereCondition(String prefix, T value, String suffix) {
            super();
            this.prefix = prefix;
            this.suffix = suffix;
            this.value = value;
        }

        public WhereCondition(String prefix, Object[] values, String suffix) {
            super();
            this.prefix = prefix;
            this.suffix = suffix;
            this.values = values;
        }

        public String getPrefix() {
            return prefix;
        }

        public void setPrefix(String prefix) {
            this.prefix = prefix;
        }

        public String getSuffix() {
            return suffix;
        }

        public void setSuffix(String suffix) {
            this.suffix = suffix;
        }

        public T getValue() {
            return value;
        }

        public void setValue(T value) {
            this.value = value;
        }

        public Object[] getValues() {
            return values;
        }

        public void setValues(Object[] values) {
            this.values = values;
        }

        public List<WhereCondition<?>> getCustomRequire() {
            return customRequire;
        }

        public void setCustomRequire(List<WhereCondition<?>> customRequire) {
            this.customRequire = customRequire;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("WhereCondition{");
            sb.append("prefix='").append(prefix).append('\'');
            sb.append(", suffix='").append(suffix).append('\'');
            sb.append(", value=").append(value);
            sb.append(", values=").append(Arrays.toString(values));
            sb.append(", customRequire=").append(customRequire);
            sb.append('}');
            return sb.toString();
        }
    }

    /**
     * order by条件集
     */
    public static class OrderByCondition {
        /**
         * 列
         */
        private String column;
        /**
         * 排序规则(默认ASC)
         */
        private String mode;

        public OrderByCondition(String column) {
            this.column = column;
            this.mode = Example.ASC;
        }

        public OrderByCondition(String column, String mode) {
            this.column = column;
            this.mode = mode;
        }

        public String getColumn() {
            return column;
        }

        public void setColumn(String column) {
            this.column = column;
        }

        public String getMode() {
            return mode;
        }

        public void setMode(String mode) {
            this.mode = mode;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("OrderByCondition{");
            sb.append("column='").append(column).append('\'');
            sb.append(", mode='").append(mode).append('\'');
            sb.append('}');
            return sb.toString();
        }
    }

    /**
     * group by条件集
     */
    public static class GroupByCondition {
        private String column;
        private String mode;

        public GroupByCondition(String column) {
            this.column = column;
        }

        public GroupByCondition(String column, String mode) {
            this.column = column;
            this.mode = mode;
        }

        public String getColumn() {
            return column;
        }

        public void setColumn(String column) {
            this.column = column;
        }

        public String getMode() {
            return mode;
        }

        public void setMode(String mode) {
            this.mode = mode;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("GroupByCondition{");
            sb.append("column='").append(column).append('\'');
            sb.append(", mode='").append(mode).append('\'');
            sb.append('}');
            return sb.toString();
        }
    }

    /**
     * 判断是否空字符串或NULL
     *
     * @param str
     * @return
     */
    public static boolean isEmpty(String str) {
        return str == null || str.trim().length() <= 0;
    }

    /**
     * 获取一个查询条件
     *
     * @param prefix
     * @param value
     * @param <T>
     * @return
     */
    public static <T> WhereCondition whereCondition(String prefix, T value) {
        return new Example.WhereCondition<T>(prefix, value);
    }

    /**
     * 获取一个查询条件
     *
     * @param prefix
     * @param suffix
     * @param <T>
     * @return
     */
    public static <T> WhereCondition whereCondition(String prefix, String suffix) {
        return new Example.WhereCondition<T>(prefix, suffix);
    }

    /**
     * 获取一个查询条件
     *
     * @param prefix
     * @param suffix
     * @param values
     * @param <T>
     * @return
     */
    public static <T> WhereCondition whereCondition(String prefix, String suffix, Object... values) {
        return new Example.WhereCondition<T>(prefix, values, suffix);
    }

    /**
     * 获取一个查询条件
     *
     * @param prefix
     * @param suffix
     * @param conditions
     * @param <T>
     * @return
     */
    public static <T> WhereCondition whereCondition(String prefix, String suffix, WhereCondition<?>... conditions) {
        List<WhereCondition<?>> list = new ArrayList<>(Arrays.asList(conditions));
        return new Example.WhereCondition<T>(prefix, suffix, list);
    }

    /**
     * 获取一个排序条件
     *
     * @param column
     * @param mode
     * @param <T>
     * @return
     */
    public static <T> OrderByCondition orderByCondition(String column, String mode) {
        OrderByCondition orderByCondition = new Example.OrderByCondition(column, mode);
        return orderByCondition;
    }

    /**
     * 获取一个默认排序条件
     *
     * @param column
     * @param <T>
     * @return
     */
    public static <T> OrderByCondition orderByCondition(String column) {
        OrderByCondition orderByCondition = new Example.OrderByCondition(column, Example.ASC);
        return orderByCondition;
    }

    /**
     * 获取一个分组汇总条件
     *
     * @param column
     * @param mode
     * @param <T>
     * @return
     */
    public static <T> GroupByCondition groupByCondition(String column, String mode) {
        GroupByCondition groupByCondition = new Example.GroupByCondition(column, mode);
        return groupByCondition;
    }

    /**
     * 获取一个默认分组汇总条件
     *
     * @param column
     * @param <T>
     * @return
     */
    public static <T> GroupByCondition groupByCondition(String column) {
        GroupByCondition groupByCondition = new Example.GroupByCondition(column);
        return groupByCondition;
    }

    /**
     * and ${column} = #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andEq(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " = ", value));
        return this;
    }

    /**
     * and ${column} in (#{value}...)
     *
     * @param column
     * @param values
     * @return
     */
    public Example<T> andIn(String column, Object... values) {
        addWhereCondition(whereCondition(" AND " + column + " IN (", ") ", values));
        return this;
    }

    /**
     * or ${column} = #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orEq(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " = ", value));
        return this;
    }

    /**
     * or ${column} in (#{value}...)
     *
     * @param column
     * @param values
     * @return
     */
    public Example<T> orIn(String column, Object... values) {
        addWhereCondition(whereCondition(" OR " + column + " IN (", ") ", values));
        return this;
    }

    /**
     * and ${column} < #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andLt(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " < ", value));
        return this;
    }


    /**
     * and ${column} <= #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andLtE(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " <= ", value));
        return this;
    }

    /**
     * or ${column} < #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orLt(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " < ", value));
        return this;
    }

    /**
     * and ${column} <= #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orLtE(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " <= ", value));
        return this;
    }

    /**
     * and ${column} > #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andGt(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " > ", value));
        return this;
    }


    /**
     * or ${column} > #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orGt(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " > ", value));
        return this;
    }

    /**
     * and ${column} >= #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andGtE(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " >= ", value));
        return this;
    }

    /**
     * or ${column} >= #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orGtE(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " >= ", value));
        return this;
    }

    /**
     * and isnull(${column})
     *
     * @param column
     * @return
     */
    public Example<T> andIsNull(String column) {
        addWhereCondition(whereCondition(" AND ISNULL(" + column, ") "));
        return this;
    }

    /**
     * and ${column} is not null
     *
     * @param column
     * @return
     */
    public Example<T> andIsNotNull(String column) {
        addWhereCondition(whereCondition(" AND " + column, " IS NOT NULL "));
        return this;
    }

    /**
     * or isnull(${column})
     *
     * @param column
     * @return
     */
    public Example<T> orIsNull(String column) {
        addWhereCondition(whereCondition(" OR ISNULL(" + column, ") "));
        return this;
    }

    /**
     * or ${column} is not null
     *
     * @param column
     * @return
     */
    public Example<T> orIsNotNull(String column) {
        addWhereCondition(whereCondition(" OR " + column, " IS NOT NULL "));
        return this;
    }

    /**
     * and ${column} <> #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> andNotEquals(String column, T value) {
        addWhereCondition(whereCondition(" AND " + column + " <> ", value));
        return this;
    }

    /**
     * or ${column} <> #{value}
     *
     * @param column
     * @param value
     * @return
     */
    public Example<T> orNotEquals(String column, T value) {
        addWhereCondition(whereCondition(" OR " + column + " <> ", value));
        return this;
    }

    /**
     * or (...)
     *
     * @param whereConditions
     * @return
     */
    public Example<T> orParent(WhereCondition<?>... whereConditions) {
        if (whereConditions == null || whereConditions.length <= 0) return this;
        String prefix = " OR (";
        String suffix = ") ";
        addWhereCondition(whereCondition(prefix, suffix, whereConditions));
        return this;
    }

    /**
     * and (...)
     *
     * @param whereConditions
     * @return
     */
    public Example<T> AndParent(WhereCondition<?>... whereConditions) {
        if (whereConditions == null || whereConditions.length <= 0) return this;
        String prefix = " AND (";
        String suffix = ") ";
        addWhereCondition(whereCondition(prefix, suffix, whereConditions));
        return this;
    }

    /**
     * not (...)
     *
     * @param whereConditions
     * @return
     */
    public Example<T> NotParent(WhereCondition<?>... whereConditions) {
        if (whereConditions == null || whereConditions.length <= 0) return this;
        String prefix = " NOT (";
        String suffix = ") ";
        addWhereCondition(whereCondition(prefix, suffix, whereConditions));
        return this;
    }
}
